package jp.wug.samples.export;

import com.google.inject.Provider;
import jp.wug.Renderer;

import java.util.Map;
import java.util.TreeMap;

public class Tree {
    private final TreeFactory treeFactory;
    private final Provider<Status> statusProvider;

    private final int id;
    private String name;
    private final Map<Integer, Tree> children = new TreeMap<Integer, Tree>();

    Tree(TreeFactory treeFactory, Provider<Status> statusProvider, int id) {
        this.statusProvider = statusProvider;
        this.treeFactory = treeFactory;
        this.id = id;
        name = "New-" + id;
    }

    public int getId() {
        return id;
    }

    public void setName(String name) {
        if ("".equals(name)) {
            throw new IllegalArgumentException("Name cannot be empty string.");
        }
        this.name = name;
    }

    public String getName() {
        return name;
    }

    private Status getStatus() {
        return statusProvider.get();
    }

    public boolean canEdit() {
        return !getStatus().isEditing();
    }

    public boolean isEditing() {
        return getStatus().isEditing(this);
    }

    public void edit() {
        if (canEdit()) {
            getStatus().edit(this);
        }
    }

    public void doneEditing() {
        getStatus().doneEditing(this);
    }

    public Form getEditForm() {
        return new Form(this);
    }

    public static class Form {
        private final Tree parent;
        private final Tree tree;

        Form(Tree tree) {
            assert tree != null;
            parent = null;
            this.tree = tree;
        }

        Form(Tree parent, Tree tree) {
            assert tree != null;
            this.parent = parent;
            this.tree = tree;
        }

        public String getName() {
            return tree.getName();
        }

        public void setName(String name) {
            tree.setName(name);
        }

        public void renderChildren(final Renderer<Integer, Form> renderer) {
            tree.renderChildren(new Renderer<Integer, Tree>() {
                public void render(Integer id, Tree value) {
                    renderer.render(id, new Form(tree, value));
                }
            });
        }

        public Form getChild(int id) {
            return new Form(tree, tree.getChild(id));
        }

        public void delete() {
            parent.delete(tree);
        }

        public void addChild() {
            tree.addChild();
        }

        public void submit() {
            tree.doneEditing();
        }
    }

    void delete(Tree tree) {
        children.remove(tree.getId());
    }

    Tree addChild() {
        Tree child = treeFactory.create();
        children.put(child.getId(), child);
        return child;
    }

    public void renderChildren(Renderer<Integer, Tree> renderer) {
        for (Tree tree : children.values()) {
            renderer.render(tree.getId(), tree);
        }
    }

    public Tree getChild(int id) {
        return children.get(id);
    }

    public Tree asTree() {
        return this;
    }
}
